package com.orcwar.gui.views;

import static com.orcwar.engine.OWConstants.TILE_SIZE;
import static com.orcwar.engine.OWConstants.BOTTOM_MENU_HEIGHT;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.WindowManager;
import android.widget.Scroller;

import com.orcwar.engine.level.OWLevelBuilder.OWLevelParameters;
import com.orcwar.gui.OWGUI;
import com.orcwar.gui.OWGUIDrawer;

public class OWCanvasView extends View {
	private static final int SCROLL_OFFSET = 500;
	
	private int mMaxScrollX;
	private int mMaxScrollY;
	private float mScaleFactor = 1.f;

	private int w, h;
	
	private boolean onShowPress;

	private GestureDetector gestureDetector;
	private ScaleGestureDetector scaleGestureDetector;
	
	/**
	 * The scroller is a simulation of the position of the View. You give it
	 * initial velocity and min/max values and it gives you coordinates over
	 * time to make a smooth movement.
	 */
	Scroller scroller;

	/**
	 * GUI manager.
	 */
	private OWGUI gui;

	public OWCanvasView(Context context, OWGUI gui) {
		super(context);
		scroller = new Scroller(context);

		this.gui = gui;
		gui.setGameView(this);

		// get a reference to the game
		final OWLevelParameters currentLevelInfo = gui.getCurrentGameInfo();

		DisplayMetrics metrics = new DisplayMetrics();
		((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
				.getDefaultDisplay().getMetrics(metrics);
		w = Math.min(metrics.widthPixels, TILE_SIZE * currentLevelInfo.getWidth());
		h = Math.min(metrics.heightPixels - BOTTOM_MENU_HEIGHT, TILE_SIZE
				* currentLevelInfo.getHeight());

		// init max scroll = size of all the tiles - window size
		mMaxScrollX = TILE_SIZE * currentLevelInfo.getWidth() - w + SCROLL_OFFSET;
		mMaxScrollY = TILE_SIZE * currentLevelInfo.getHeight() - h + SCROLL_OFFSET;

		// build gestureDetector to handle scroll/fling events
		gestureDetector = new GestureDetector(getContext(),
				new GestureDetector.OnGestureListener() {

					@Override
					public boolean onDown(MotionEvent arg0) {
						if (!scroller.isFinished()) { // is flinging
							scroller.forceFinished(true); // to stop flinging on
															// touch
						}
						return true;
					}

					@Override
					public boolean onFling(MotionEvent arg0, MotionEvent arg1,
							float vX, float vY) {
						if (onShowPress) return true;
						scroller.fling(getScrollX(), getScrollY(), -(int) vX,
								-(int) vY, -SCROLL_OFFSET, (int) mMaxScrollX, -SCROLL_OFFSET,
								(int) mMaxScrollY);
						return true;
					}

					@Override
					public void onLongPress(MotionEvent arg0) {
						// TODO Auto-generated method stub

					}

					@Override
					public boolean onScroll(MotionEvent arg0, MotionEvent arg1,
							float distanceX, float distanceY) {
						if (onShowPress) return true;
						
						// check that the scroll does not go outside
						int dy;
						int dx;
						if (getScrollX() + distanceX < -SCROLL_OFFSET) {
							dx = -getScrollX() - SCROLL_OFFSET;
						} else if (getScrollX() + distanceX > currentLevelInfo
								.getWidth() * TILE_SIZE - w + SCROLL_OFFSET) {
							dx = currentLevelInfo.getWidth() * TILE_SIZE - w
									- getScrollX() + SCROLL_OFFSET;
						} else {
							dx = (int) distanceX;
						}
						if (getScrollY() + distanceY < -SCROLL_OFFSET) {
							dy = -getScrollY() - SCROLL_OFFSET;
						} else if (getScrollY() + distanceY > currentLevelInfo
								.getHeight() * TILE_SIZE - h + SCROLL_OFFSET) {
							dy = currentLevelInfo.getHeight() * TILE_SIZE - h
									- getScrollY() + SCROLL_OFFSET;
						} else {
							dy = (int) distanceY;
						}
						scrollBy(dx, dy);
						return true;
					}

					@Override
					public void onShowPress(MotionEvent e) {
						// get position on the event
						int x = (int) ((e.getX() + getScrollX()) / (TILE_SIZE * mScaleFactor));
						int y = (int) ((e.getY() + getScrollY()) / (TILE_SIZE * mScaleFactor));
						onShowPress = OWCanvasView.this.gui.onShowPressed(x, y);
					}

					@Override
					public boolean onSingleTapUp(MotionEvent e) {
						// get position on the event
						int x = (int) ((e.getX() + getScrollX()) / (TILE_SIZE * mScaleFactor));
						int y = (int) ((e.getY() + getScrollY()) / (TILE_SIZE * mScaleFactor));
						OWCanvasView.this.gui.handleTap(x, y);
						return true;
					}
				});

		
		scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {

			@Override
			public boolean onScale(ScaleGestureDetector detector) {
				mScaleFactor *= detector.getScaleFactor();

		        // Don't let the object get too small or too large.
		        mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
		        if (mScaleFactor < 0.4f) mScaleFactor = 0.4f;
		        else if (mScaleFactor > 1) mScaleFactor = 1f;

		        return true;
			}

			@Override
			public boolean onScaleBegin(ScaleGestureDetector detector) {
				return true;
			}

			@Override
			public void onScaleEnd(ScaleGestureDetector detector) {
		        if (mScaleFactor < 0.4f) mScaleFactor = 0.4f;
		        else if (mScaleFactor < 0.5f) mScaleFactor = 0.4f;
		        else if (mScaleFactor < 0.6f) mScaleFactor = 0.6f;
		        else if (mScaleFactor < 0.7f) mScaleFactor = 0.7f;
		        else if (mScaleFactor < 0.8f) mScaleFactor = 0.8f;
		        else if (mScaleFactor < 0.9f) mScaleFactor = 0.9f;
		        else mScaleFactor = 1f;
		        
		        Log.w("SCALE", "Scale factor : " + mScaleFactor);
			}
			
		});
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.save();
		canvas.scale(mScaleFactor, mScaleFactor);
	    //Background color around the map
	    canvas.drawColor(Color.BLACK);
	    
		OWGUIDrawer.getInstance().draw(canvas);

		// scrollTo invalidates, so until animation won't finish it will be
		// called and will call again onDraw() (used after a Scroller.fling() )
		if (scroller.computeScrollOffset()) {
			scrollTo(scroller.getCurrX(), scroller.getCurrY());
		}
		
		
		canvas.restore();
	}

	@Override
	public boolean onTouchEvent(MotionEvent e) {
		if (e.getAction() == MotionEvent.ACTION_UP) {
			onShowPress = false;
			// get position on the event
			int x = (int) ((e.getX() + getScrollX()) / (TILE_SIZE * mScaleFactor));
			int y = (int) ((e.getY() + getScrollY()) / (TILE_SIZE * mScaleFactor));
			this.gui.onUp(x,y);
		}
		scaleGestureDetector.onTouchEvent(e);
		gestureDetector.onTouchEvent(e);
		
		return true;
	}

}
